首先了解this
如果想用好这几个方法,需要先了解this被调用方式不同而导致值不同的各种情况,然后就会认识到使用这几个方法的原因在哪里。(可以指定this的值)
全局上下文中this指向全局对象,函数上下文this取决于被调用的方式
例:
- 在非严格模式下,全局调用函数this默认指向全局(window)
var a = 3
function exp(){
var a = 4
console.log(this.a)
}
var b = exp()
// 输出3
- 在严格模式下,因为this为其进入上下文时的值,所以为undefined
function exp(){
"use strict"
return this
}
console.log(exp() === undefined)
// 输出 true
下面分析各个调用场合下this的值
作为函数被直接调用
上面已经写出了这种情况,值得注意的是,我们往往并不需要this值为window
作为方法被调用
作为方法被调用时,this指向方法所在的对象上
例:
var exp = {
obj: function context() {
var text = "hello"
return this
}
}
console.log(exp.obj() === exp)
var a = exp.obj()
console.log(a === exp)
var b = exp.obj
console.log(b() === window) //true,,注意这里当对象的方法被全局调用后this是b的this,则是window
//均输出 true
作为构造函数被调用
我们知道构造函数创建一个对象的过程
- 创建新对象
- 新对象作为this指向的对象
- 为新对象添加方法、属性、、并返回对象
需要注意的地方:构造函数返回一个非对象类型时,创建新对象时并不妨碍this的使用,也会返回新创建的对象。但是当构造函数显示返回一个对象时就会将这个对象赋值给变量,this的使用则无效。
function Fn (){
this.obj = function() {
return this
}
}
let a = new Fn()
console.log(a.obj() === Fn) // false
console.log(a.obj() === a) //true
let newObj = {
name: "小明"
}
function reObj (){
this.name = "康康"
return newObj
}
let b = new reObj()
console.log(b.name) //小明,返回的对象是newObj
进入正题,在这么多变化中随时都可能出错,所以call()、apply()、bind()就提供了一个可以指定this的方式
方法的使用
-
call()
这个方法接受多个参数,第一个参数是指定的this值,剩下的都是调用的函数的参数列表
fn.call(this, arg1, arg2, ...);
如果第一个参数需要是对象,如果传入了数字、字符串、布尔值的话this会指向该原始值的自动包装对象function f(){ console.log(this) console.log(arguments) } f.call() // window f.call({name:'小明'}) // {name: '小明'}, [] f.call({name:'小红'},1) // {name: '小红'}, [1] f.call({name:'康康'},1,2) // {name: '康康'}, [1,2]
-
apply()
apply() 与call()区别在于第二个参数接受的是一个包含多个参数的数组,对于一些方法需要传入的参数不能使数组,可以使用apply()调用函数使其可以使用数组作为参数。
var a = [1,2,3,4,5,6,7,8,9] sum.apply(null,a) //将参数a全都传入,它会把参数作为数组传入。 //求数组的最大元素 Math.max.apply(null,[1,2,6]) // 6
很多使用场景都可以被es6里的扩展运算符替代
-
bind()
bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值.
this.name = "大牛" let obj = { name: "康康", age: 18, city:"上海" } let newObj = { name: "小明", sayName: function() { console.log(this.name) } } newObj.sayName()// 小明 let a = newObj.sayName.bind(obj) a() //康康 let b = newObj.sayName b() //大牛
-
箭头函数
这里说一下箭头函数,因为箭头函数没有this,所以会根据作用域链进行寻找this,这也衍生了很多用法,比如在setTimeout里经常出现的上下文(作用域)问题,如果不使用箭头函数,在函数运行时作用域就变成了全局,使用箭头函数会使函数里用到的this绑定在setTimeout的作用域上var timer = { fn1() { setTimeout(function(){ console.log(this) }, 10) }, fn2() { setTimeout(()=>{ console.log(this) },20) }, fn3: ()=> { setTimeout(()=>{ console.log(this) },30) } } timer.fn1() //window timer.fn2() // timer timer.fn3() //window //第一个在执行时是在全局调用,相当于 fn1.call(undefined) // 第二个使用箭头函数自身没this,使this 指向了timer // 第三个自身没this的情况下,根据箭头函数的规则找到了最外层全局(window)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。